#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<string.h>
#define NUM 128     
#define CMD_NUM 64  
int main()
{ 
    while(1)
    {
        char command[NUM];
        char* argv[CMD_NUM] = {NULL};
         memset(command,0,sizeof(command));
        //1.打印提示符
        printf("[who@host dir]");
        fflush(stdout);
        //2.获取用户输入

        //方式1:
        // fgets(command,NUM-1,stdin);//从键盘当中读取  ls -l\n
        // command[strlen(command)-1] = '\0';
        
        //方式2
        ssize_t n = read(0,command,NUM-1); //ls -l\n
        command[n-1] = '\0';

        //3.命令行解析
        const char* sep = " ";
        argv[0] = strtok(command,sep);
        int index =1;
        while(argv[index++] = strtok(NULL,sep)) ;
        
        //3.2 判断要执行的是否是内建命令
        if(strcmp("cd",argv[0]) == 0)
        {
            if(argv[1])
                chdir(argv[1]);
            continue;
        }
        //4.创建子进程
        pid_t id = fork();
        if(id == 0) //child
        {
            //5.进程替换
            //5.1因为指令的选项保存在数组当中，所以要选择带v的
            //5.2因为数组的第一个参数就是要执行的命令，是不带路径的，所以我们要选择带p
            //综上所述：要选择的exec*系列函数为：execvp  
            execvp(argv[0],argv);
            exit(1);//来到这里说明进程替换失败
        }
        else if(id < 0)
        {
            perror("fork :");//创建子进程失败
            exit(2);
        }
        //parent
        //6.等待子进程退出
        int status = 0;
        int ret = waitpid(id,&status,0);
        if(ret  > 0)
        {
            printf("exitcode:%d exitSignal:%d\n",(status >> 8)&0xff,status&0x7f);
        }

    }
    return 0;
}